import express from "express";
import cors from "cors";
import axios from "axios";
import http from "http";
import path from "path";
import { fileURLToPath } from "url";
import { dirname } from "path";
import open from "open";
import fs from "fs";
import multer from "multer";
import pdf from "pdf-parse";
import { promisify } from "util";

// 添加OCR相关导入
import { createWorker } from "tesseract.js";
import { fromPath } from "pdf2pic";
// 添加mammoth导入，用于处理Word文档
import mammoth from "mammoth";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const app = express();
const port = 3000;

// 添加用于存储会话历史的文件路径
const SESSIONS_FILE = path.join(__dirname, "sessions.json");

// 添加用于存储向量数据的文件路径
const VECTORS_FILE = path.join(__dirname, "vectors.json");

// 配置文件上传
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    const uploadDir = path.join(__dirname, "uploads");
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + "-" + file.originalname);
  },
});

const upload = multer({ storage: storage });

app.use(cors());
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.static(__dirname + "/static"));

// 添加上传文件夹为静态资源目录
app.use("/uploads", express.static(path.join(__dirname, "uploads")));

// 初始化OCR worker
let ocrWorker;

// 初始化OCR功能
async function initializeOCR() {
  try {
    console.log("开始初始化OCR...");

    // 检查本地tessdata目录是否存在
    const localTessdataPath = path.join(__dirname, "tessdata");
    const useLocalTessdata = fs.existsSync(localTessdataPath);

    if (useLocalTessdata) {
      console.log("使用本地tessdata目录:", localTessdataPath);
      ocrWorker = await createWorker({
        langPath: localTessdataPath,
        gzip: false,
        logger: (m) => {
          if (m.status === "loading") {
            console.log("OCR加载中:", m.status, m.progress);
          } else if (m.status === "loaded") {
            console.log("OCR加载完成:", m.status);
          } else if (m.status === "initializing") {
            console.log("OCR初始化中:", m.status, m.progress);
          }
        },
      });
    } else {
      console.log("未找到本地tessdata目录，使用默认配置");
      ocrWorker = await createWorker({
        logger: (m) => {
          if (m.status === "loading") {
            console.log("OCR加载中:", m.status, m.progress);
          } else if (m.status === "loaded") {
            console.log("OCR加载完成:", m.status);
          } else if (m.status === "initializing") {
            console.log("OCR初始化中:", m.status, m.progress);
          }
        },
      });
    }

    await ocrWorker.load();
    await ocrWorker.loadLanguage("eng+chi_sim");
    await ocrWorker.initialize("eng+chi_sim");
    console.log("OCR初始化成功");
  } catch (error) {
    console.error("OCR初始化失败:", error.message);
    // 尝试仅使用英文语言包
    try {
      console.log("尝试使用英文语言包...");
      if (ocrWorker) {
        await ocrWorker.terminate();
      }

      const localTessdataPath = path.join(__dirname, "tessdata");
      const useLocalTessdata = fs.existsSync(localTessdataPath);

      if (useLocalTessdata) {
        ocrWorker = await createWorker({
          langPath: localTessdataPath,
          gzip: false,
          logger: (m) => console.log("OCR英文语言包加载中:", m.status),
        });
      } else {
        ocrWorker = await createWorker({
          logger: (m) => console.log("OCR英文语言包加载中:", m.status),
        });
      }

      await ocrWorker.load();
      await ocrWorker.loadLanguage("eng");
      await ocrWorker.initialize("eng");
      console.log("OCR使用英文语言包初始化成功");
    } catch (englishError) {
      console.error("OCR英文语言包初始化也失败:", englishError.message);
      // 最后的降级方案 - 不使用OCR
      ocrWorker = null;
      console.log("OCR功能不可用，将跳过图片文字识别");
    }
  }
}

// 调用初始化函数
initializeOCR();

// 添加一个函数来检查OCR是否可用
function isOCRAvailable() {
  return ocrWorker !== null && ocrWorker !== undefined;
}

const agent = new http.Agent({ keepAlive: true });

// 辅助函数：读取所有会话
function readSessions() {
  try {
    if (fs.existsSync(SESSIONS_FILE)) {
      const data = fs.readFileSync(SESSIONS_FILE, "utf8");
      return JSON.parse(data);
    }
  } catch (err) {
    console.error("读取会话记录错误:", err);
  }
  return {};
}

// 辅助函数：保存向量数据
function saveVectors(vectors) {
  try {
    fs.writeFileSync(VECTORS_FILE, JSON.stringify(vectors, null, 2));
  } catch (err) {
    console.error("保存向量数据错误:", err);
  }
}

// 辅助函数：读取向量数据
function readVectors() {
  try {
    if (fs.existsSync(VECTORS_FILE)) {
      const data = fs.readFileSync(VECTORS_FILE, "utf8");
      return JSON.parse(data);
    }
  } catch (err) {
    console.error("读取向量数据错误:", err);
  }
  return [];
}

// 辅助函数：保存所有会话
function saveSessions(sessions) {
  try {
    fs.writeFileSync(SESSIONS_FILE, JSON.stringify(sessions, null, 2));
  } catch (err) {
    console.error("保存会话记录错误:", err);
  }
}

// 生成唯一会话ID
function generateSessionId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
}

// 添加OCR文本提取函数
async function extractTextWithOCR(pdfPath) {
  console.log("开始OCR处理:", pdfPath);

  try {
    // 检查系统是否安装了GraphicsMagick或ImageMagick
    const { execSync } = require("child_process");
    let hasGraphicsTool = false;

    try {
      // 尝试检查gm是否存在
      execSync("gm -version", { stdio: "ignore" });
      hasGraphicsTool = true;
      console.log("检测到GraphicsMagick");
    } catch (gmError) {
      try {
        // 尝试检查convert是否存在 (ImageMagick)
        execSync("convert -version", { stdio: "ignore" });
        hasGraphicsTool = true;
        console.log("检测到ImageMagick");
      } catch (convertError) {
        console.log("未检测到GraphicsMagick或ImageMagick");
      }
    }

    // 如果没有安装图形处理工具，直接返回空文本并提示用户
    if (!hasGraphicsTool) {
      console.log(
        "警告: 系统未安装GraphicsMagick或ImageMagick，无法处理图片型PDF"
      );
      console.log("请安装GraphicsMagick或ImageMagick以启用OCR功能:");
      console.log(
        "  Windows: 下载并安装GraphicsMagick (http://www.graphicsmagick.org/download.html)"
      );
      console.log("  macOS: brew install graphicsmagick");
      console.log("  Linux: sudo apt-get install graphicsmagick");
      return "";
    }

    // 获取文件的基本信息
    const parsedPath = path.parse(pdfPath);
    const cleanFileName = parsedPath.name.replace(/[^\w\-_.]/g, "_"); // 清理文件名中的特殊字符

    // 配置pdf2pic
    const options = {
      density: 150, // 进一步降低DPI以减少内存使用和提高稳定性
      savename: cleanFileName,
      savedir: parsedPath.dir,
      format: "png",
      width: 1240, // A4纸150DPI宽度
      height: 1754, // A4纸150DPI高度
    };

    const storeAsImage = fromPath(pdfPath, options);

    // 将PDF转换为图片
    console.log("正在将PDF转换为图片...");
    const pageImages = await storeAsImage.bulk(-1); // 转换所有页面
    console.log(`PDF转换完成，共生成 ${pageImages.length} 页图片`);

    // 初始化Tesseract.js worker
    const localTessdataPath = path.join(__dirname, "tessdata");
    const useLocalTessdata = fs.existsSync(localTessdataPath);

    let worker;
    if (useLocalTessdata) {
      worker = await createWorker({
        langPath: localTessdataPath,
        gzip: false,
        logger: null, // 禁用logger以避免DataCloneError
      });
    } else {
      worker = await createWorker();
    }

    await worker.load();
    await worker.loadLanguage("eng+chi_sim");
    await worker.initialize("eng+chi_sim");

    let ocrText = "";

    // 对每一页图片进行OCR识别
    for (let i = 0; i < pageImages.length; i++) {
      console.log(`正在OCR识别第 ${i + 1} 页...`);
      const imagePath = pageImages[i].path;
      try {
        const {
          data: { text },
        } = await worker.recognize(imagePath);
        ocrText += text + "\n\n"; // 添加两个换行符分隔页面
      } catch (recognizeError) {
        console.error(`第${i + 1}页OCR识别失败:`, recognizeError.message);
      }

      // 删除临时图片文件
      try {
        fs.unlinkSync(imagePath);
      } catch (unlinkErr) {
        console.warn(`删除临时文件失败: ${imagePath}`, unlinkErr.message);
      }
    }

    console.log("OCR处理完成，总文本长度:", ocrText.length);
    return ocrText;
  } catch (error) {
    console.error("OCR处理失败:", error.message);
    // 尝试清理可能残留的临时文件
    try {
      const parsedPath = path.parse(pdfPath);
      const tempFilesPattern = path.join(
        parsedPath.dir,
        parsedPath.name + "-*.*"
      );
      const tempFiles = fs
        .readdirSync(parsedPath.dir)
        .filter((file) => file.startsWith(parsedPath.name + "-"))
        .map((file) => path.join(parsedPath.dir, file));

      tempFiles.forEach((file) => {
        try {
          fs.unlinkSync(file);
        } catch (e) {
          // 忽略删除失败
        }
      });
    } catch (cleanupErr) {
      console.warn("清理临时文件失败:", cleanupErr.message);
    }

    // 提供更友好的错误信息
    if (
      error.message.includes("Could not execute GraphicsMagick/ImageMagick")
    ) {
      console.log("请安装GraphicsMagick或ImageMagick以启用OCR功能:");
      console.log(
        "  Windows: 下载并安装GraphicsMagick (http://www.graphicsmagick.org/download.html)"
      );
      console.log("  macOS: brew install graphicsmagick");
      console.log("  Linux: sudo apt-get install graphicsmagick");
      throw new Error("系统未安装GraphicsMagick或ImageMagick，请安装后再试");
    }

    throw new Error(`OCR处理失败: ${error.message}`);
  } finally {
    // 确保worker被终止
    if (worker) {
      try {
        await worker.terminate();
      } catch (terminateErr) {
        console.warn("终止OCR worker失败:", terminateErr.message);
      }
    }
  }
}

// 简单的文本切片函数
function chunkText(text, chunkSize = 500, overlap = 100) {
  // 处理空文本或空白文本的情况
  if (!text || text.trim().length === 0) {
    console.log("文本为空或仅包含空白字符");
    return [];
  }

  const chunks = [];
  const cleanedText = text.replace(/\s+/g, " ").trim(); // 清理多余的空白字符
  const words = cleanedText.split(/\s+/);

  console.log("文本总词数:", words.length);

  // 如果文本词数少于10个，直接作为一个块
  if (words.length < 10) {
    console.log("文本词数少于10个，直接作为一个块");
    return [cleanedText];
  }

  for (let i = 0; i < words.length; i += chunkSize - overlap) {
    const chunk = words.slice(i, i + chunkSize).join(" ");
    if (chunk.trim().length > 0) {
      chunks.push(chunk.trim());
    }
  }

  console.log("切片后的块数量:", chunks.length);
  return chunks;
}

// 模拟向量化函数（实际应用中应该使用真实的向量模型）
function vectorizeText(text) {
  // 这里我们使用一个简单的模拟向量化方法
  // 实际应用中应该使用如 text2vec、BERT 等模型
  const vector = [];
  const seed = text
    .split("")
    .reduce((acc, char) => acc + char.charCodeAt(0), 0);
  for (let i = 0; i < 384; i++) {
    // 使用 384 维向量，类似 BERT
    vector.push(Math.sin(seed + i) * 0.5 + 0.5);
  }
  return vector;
}

// 简单的向量相似度计算（余弦相似度）
function cosineSimilarity(vecA, vecB) {
  let dotProduct = 0;
  let magnitudeA = 0;
  let magnitudeB = 0;

  for (let i = 0; i < vecA.length; i++) {
    dotProduct += vecA[i] * vecB[i];
    magnitudeA += vecA[i] * vecA[i];
    magnitudeB += vecB[i] * vecB[i];
  }

  magnitudeA = Math.sqrt(magnitudeA);
  magnitudeB = Math.sqrt(magnitudeB);

  if (magnitudeA === 0 || magnitudeB === 0) return 0;
  return dotProduct / (magnitudeA * magnitudeB);
}

app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "/static", "/index.html"));
});

app.post("/chat-stream", async (req, res) => {
  const { prompt, history = [] } = req.body;

  if (!prompt) {
    return res.status(400).json({ error: "Missing prompt" });
  }

  // 限制历史记录数量，只保留最近的10条消息（5轮对话）
  const MAX_HISTORY_LENGTH = 10;
  const recentHistory = history.slice(-MAX_HISTORY_LENGTH);

  // 检查历史记录是否已包含当前用户输入
  let messages = [
    { role: "system", content: "你是一个中文 AI 助手。" },
    ...recentHistory,
  ];

  // 如果历史记录末尾没有当前prompt，则添加
  const lastMessage = recentHistory[recentHistory.length - 1];
  if (
    !lastMessage ||
    lastMessage.role !== "user" ||
    lastMessage.content !== prompt
  ) {
    messages.push({ role: "user", content: prompt });
  }

  try {
    const response = await axios({
      method: "post",
      url: "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
      headers: {
        Authorization:
          "Bearer " +
          (process.env.DASHSCOPE_API_KEY ||
            "sk-4cd59a1b320540a0869131d1f20d284b"),
        "Content-Type": "application/json",
      },
      data: {
        model: "qwen-plus",
        messages,
        stream: true,
      },
      responseType: "stream",
      httpAgent: agent,
      proxy: false, // 强制禁用代理
    });

    // 设置响应头（标准文本流）
    res.setHeader("Content-Type", "text/plain; charset=utf-8");
    res.setHeader("Transfer-Encoding", "chunked");

    // 逐块读取数据并发送给前端
    response.data.on("data", (chunk) => {
      // 处理流式响应数据
      const lines = chunk.toString().split("\n").filter(Boolean);

      for (const line of lines) {
        try {
          // 处理SSE格式的数据
          if (line.startsWith("data: ")) {
            const data = line.slice(6);
            if (data === "[DONE]") {
              res.end();
              return;
            }

            const json = JSON.parse(data);
            const content = json.choices?.[0]?.delta?.content;
            if (content) {
              res.write(content);
            }
          }
        } catch (e) {
          console.warn("⚠️ 跳过非 JSON 行:", line);
        }
      }
    });

    response.data.on("end", () => res.end());
    response.data.on("error", (err) => {
      console.error("❌ DashScope 流异常:", err.message);
      res.end();
    });
  } catch (err) {
    console.error("❌ 接口调用失败:", err.message);
    res.status(500).end("Internal Server Error");
  }
});

// 添加新的API端点用于获取所有会话
app.get("/sessions", (req, res) => {
  const sessions = readSessions();
  res.json(sessions);
});

// 添加文件上传端点
app.post("/upload", upload.single("file"), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: "No file uploaded" });
  }

  try {
    let text = "";

    console.log("开始处理文件:", req.file.originalname);
    console.log("文件MIME类型:", req.file.mimetype);
    console.log("文件路径:", req.file.path);

    // 根据文件类型处理文件
    if (req.file.mimetype === "application/pdf") {
      console.log("检测到PDF文件，开始解析");
      const dataBuffer = fs.readFileSync(req.file.path);
      console.log("文件大小 (字节):", dataBuffer.length);
      const data = await pdf(dataBuffer);
      text = data.text;
      console.log("PDF解析完成，文本长度:", text.length);
      // 如果提取的文本很少，可能是图片型PDF，尝试OCR
      if (text.trim().length < 50) {
        console.log("文本内容过少，可能是图片型PDF，尝试OCR处理");
        try {
          const ocrText = await extractTextWithOCR(req.file.path);
          if (ocrText.trim().length > 0) {
            text = ocrText;
            console.log("PDF OCR处理完成，文本长度:", text.length);
          } else {
            console.log("OCR未返回有效文本，使用原始文本");
          }
        } catch (ocrError) {
          console.error("PDF OCR处理失败:", ocrError.message);
          // 即使OCR失败，也继续处理，避免整个请求失败
          // 向用户返回友好的错误信息
          console.log("将继续使用提取到的原始PDF文本（可能为空）");
        }
      }
    } else if (req.file.mimetype.startsWith("image/")) {
      // 处理图片文件
      console.log("检测到图片文件，开始OCR处理");
      if (isOCRAvailable()) {
        try {
          console.log("使用OCR识别图片:", req.file.path);

          // 为图片处理创建独立的worker实例
          const localTessdataPath = path.join(__dirname, "tessdata");
          const useLocalTessdata = fs.existsSync(localTessdataPath);

          let imageWorker;
          if (useLocalTessdata) {
            imageWorker = await createWorker({
              langPath: localTessdataPath,
              gzip: false,
            });
          } else {
            imageWorker = await createWorker();
          }

          await imageWorker.load();
          await imageWorker.loadLanguage("eng+chi_sim");
          await imageWorker.initialize("eng+chi_sim");

          const {
            data: { text: ocrText },
          } = await imageWorker.recognize(req.file.path);
          text = ocrText;
          console.log("OCR处理完成，文本长度:", text.length);

          // 终止worker
          await imageWorker.terminate();
        } catch (ocrError) {
          console.error("OCR处理失败:", ocrError.message);
          text = "";
        }
      } else {
        console.log("OCR未初始化，无法处理图片文件");
        text = "";
      }
    } else if (
      req.file.mimetype ===
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ||
      req.file.path.endsWith(".docx")
    ) {
      // 处理Word文档 (.docx)
      console.log("检测到Word文档，开始解析");
      try {
        const result = await mammoth.extractRawText({ path: req.file.path });
        text = result.value;
        console.log("Word文档解析完成，文本长度:", text.length);
      } catch (docxError) {
        console.error("Word文档解析失败:", docxError.message);
        text = "";
      }
    } else if (
      req.file.mimetype === "text/markdown" ||
      req.file.mimetype === "text/plain" ||
      req.file.path.endsWith(".md") ||
      req.file.path.endsWith(".txt")
    ) {
      text = fs.readFileSync(req.file.path, "utf8");
    } else {
      // 尝试作为文本文件处理
      text = fs.readFileSync(req.file.path, "utf8");
    }

    console.log("处理前文本长度:", text.length);
    console.log("处理前文本预览:", text.substring(0, 100));

    // 文本切片
    const chunks = chunkText(text);
    console.log('生成的文本块数量:', chunks.length);
    if (chunks.length > 0) {
      console.log('第一个文本块预览:', chunks[0].substring(0, 100));
    }
    
    // 向量化并保存
    const vectors = readVectors();
    
    // 删除同名文件的旧数据，避免重复
    const filteredVectors = vectors.filter(vec => vec.filename !== req.file.originalname);
    console.log(`删除了 ${vectors.length - filteredVectors.length} 个旧的文本块`);
    
    const newVectors = chunks.map((chunk, index) => ({
      id: `${req.file.filename}-${index}`,
      filename: req.file.originalname,
      content: chunk,
      vector: vectorizeText(chunk)
    }));
    
    filteredVectors.push(...newVectors);
    saveVectors(filteredVectors);

    // 删除上传的文件（可选）
    fs.unlinkSync(req.file.path);

    res.json({ 
      success: true, 
      message: `File processed successfully. Generated ${chunks.length} chunks.`,
      chunks: chunks.length
    });
  } catch (err) {
    console.error("❌ 文件处理失败:", err.message);
    console.error("❌ 错误堆栈:", err.stack);

    // 提供更友好的错误信息
    let errorMessage = "File processing failed";
    if (
      err.message.includes("GraphicsMagick") ||
      err.message.includes("ImageMagick")
    ) {
      errorMessage =
        "系统未安装GraphicsMagick或ImageMagick，无法处理图片型PDF文件。请安装相应软件后再试。";
    }

    res.status(500).json({ error: errorMessage, details: err.message });
  }
});

// 添加向量检索端点
app.post("/vector-search", (req, res) => {
  const { query } = req.body;

  if (!query) {
    return res.status(400).json({ error: "Missing query" });
  }

  try {
    const vectors = readVectors();
    const queryVector = vectorizeText(query);

    // 计算相似度并排序
    const similarities = vectors.map((vec) => ({
      ...vec,
      similarity: cosineSimilarity(queryVector, vec.vector),
    }));

    // 获取最相似的前5个结果
    const topResults = similarities
      .sort((a, b) => b.similarity - a.similarity)
      .slice(0, 5);

    res.json(topResults);
  } catch (err) {
    console.error("❌ 向量检索失败:", err.message);
    res.status(500).json({ error: "Vector search failed" });
  }
});

// 添加新的API端点用于创建新会话
app.post("/sessions", (req, res) => {
  const sessions = readSessions();
  const sessionId = generateSessionId();
  const sessionName =
    req.body.name || `会话 ${Object.keys(sessions).length + 1}`;
  const sessionMode = req.body.mode || "rag"; // 默认为RAG模式

  sessions[sessionId] = {
    id: sessionId,
    name: sessionName,
    mode: sessionMode, // 添加mode属性
    history: [],
    createdAt: new Date().toISOString(),
  };

  saveSessions(sessions);
  res.json(sessions[sessionId]);
});

// 添加新的API端点用于更新会话历史
app.put("/sessions/:id", (req, res) => {
  const sessions = readSessions();
  const sessionId = req.params.id;
  const { history, name, mode } = req.body; // 添加mode属性

  if (!sessions[sessionId]) {
    return res.status(404).json({ error: "Session not found" });
  }

  if (Array.isArray(history)) {
    sessions[sessionId].history = history;
  }

  if (name) {
    sessions[sessionId].name = name;
  }

  // 更新mode属性
  if (mode) {
    sessions[sessionId].mode = mode;
  }

  saveSessions(sessions);
  res.json({ success: true });
});

// 添加新的API端点用于删除会话
app.delete("/sessions/:id", (req, res) => {
  const sessions = readSessions();
  const sessionId = req.params.id;
  
  if (!sessions[sessionId]) {
    return res.status(404).json({ error: "Session not found" });
  }
  
  delete sessions[sessionId];
  saveSessions(sessions);
  res.json({ success: true });
});

// 添加获取向量数据库中文件列表的端点
app.get("/vector-files", (req, res) => {
  try {
    const vectors = readVectors();
    
    // 提取唯一的文件名
    const files = {};
    vectors.forEach(vec => {
      if (!files[vec.filename]) {
        files[vec.filename] = {
          filename: vec.filename,
          chunks: 0
        };
      }
      files[vec.filename].chunks++;
    });
    
    const fileList = Object.values(files);
    res.json(fileList);
  } catch (err) {
    console.error("❌ 获取文件列表失败:", err.message);
    res.status(500).json({ error: "Failed to retrieve file list" });
  }
});

// 添加删除指定文件的端点
app.delete("/vector-files/:filename", (req, res) => {
  try {
    const filename = decodeURIComponent(req.params.filename);
    const vectors = readVectors();
    
    // 过滤掉指定文件名的向量数据
    const filteredVectors = vectors.filter(vec => vec.filename !== filename);
    
    // 检查是否有数据被删除
    if (filteredVectors.length === vectors.length) {
      return res.status(404).json({ error: "File not found" });
    }
    
    // 保存更新后的向量数据
    saveVectors(filteredVectors);
    
    res.json({ 
      success: true, 
      message: `File ${filename} deleted successfully`,
      deletedChunks: vectors.length - filteredVectors.length
    });
  } catch (err) {
    console.error("❌ 删除文件失败:", err.message);
    res.status(500).json({ error: "Failed to delete file" });
  }
});

app.listen(port, () => {
  console.log(`🚀 Ollama 服务代理已启动: http://localhost:${port}`);
  open(`http://localhost:${port}`);
});
